#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/platform_device.h> 
#include <linux/fb.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/delay.h>
//#include <linux/kthread.h>
//#include <linux/dma-mapping.h>

#define LCD_W			160
#define LCD_H			80
#define REFRESH_TIME	1000

struct st7735s_st
{
	int gpio_cs;
	int gpio_dc;
	int gpio_rst;
	int gpio_dio;
	int gpio_sck;

	u8 *v_addr;
	struct fb_info *fbi;
	struct timer_list timer; 	//记录线程对象的地址，此线程专用于把显存数据发送到屏的驱动ic

	struct device_node *node;
};
static struct st7735s_st st7735sDev;

static void show_fb(struct st7735s_st *me);
struct fb_ops fops = {};

static void timer_func(struct timer_list *timer)
{
	show_fb(&st7735sDev);
	mod_timer(&st7735sDev.timer, jiffies+msecs_to_jiffies(REFRESH_TIME));
}

static int myfb_new(struct st7735s_st *dev)
{
    u8 *v_addr;
    u32 p_addr;

//	if (dma_set_mask(dev->dev, DMA_BIT_MASK(24)))
//		return -EINVAL;
//	v_addr = dma_alloc_coherent(dev->dev, X*Y*4, &p_addr, GFP_KERNEL);
//		return -ENOMEM;
//	data->thread = kthread_run(thread_func, fbi, spi->modalias);

	v_addr = kzalloc(sizeof(char)*LCD_W*LCD_H*4, GFP_KERNEL);
	p_addr = (u32)v_addr;
	dev->v_addr = v_addr;

    //额外分配100字节空间
    dev->fbi = framebuffer_alloc(1, NULL);

    dev->fbi->var.xres 				= LCD_W;
    dev->fbi->var.yres 				= LCD_H;
    dev->fbi->var.xres_virtual 		= LCD_W;
    dev->fbi->var.yres_virtual 		= LCD_H;
    dev->fbi->var.bits_per_pixel 	= 32; 		// 屏是rgb565, 但QT程序只能支持32位.还需要在刷图时把32位的像素数据转换成rgb565
    dev->fbi->var.red.offset 		= 16;
    dev->fbi->var.red.length 		= 8;
    dev->fbi->var.green.offset 		= 8;
    dev->fbi->var.green.length 		= 8;
    dev->fbi->var.blue.offset 		= 0;
    dev->fbi->var.blue.length 		= 8;

    strcpy(dev->fbi->fix.id, "myfb");
    dev->fbi->fix.smem_start 		= p_addr; 				//显存的物理地址
    dev->fbi->fix.smem_len 			= LCD_W*LCD_H*4; 
    dev->fbi->fix.type 				= FB_TYPE_PACKED_PIXELS;
    dev->fbi->fix.visual 			= FB_VISUAL_TRUECOLOR;
    dev->fbi->fix.line_length 		= LCD_W*4;

    dev->fbi->fbops 				= &fops;
    dev->fbi->screen_base 			= v_addr; 				//显存虚拟地址
    dev->fbi->screen_size 			= LCD_W*LCD_H*4; 		//显存大小

    register_framebuffer(dev->fbi); 

	timer_setup(&dev->timer, timer_func, 0);
	mod_timer(&dev->timer, jiffies+msecs_to_jiffies(REFRESH_TIME));
	
    return 0;    
}

static void myfb_del(struct st7735s_st *dev) //此函数在spi设备驱动remove时被调用
{
    struct fb_info *fbi = dev->fbi;
	del_timer_sync(&dev->timer);
	kfree(dev->v_addr);
	unregister_framebuffer(fbi);
    framebuffer_release(fbi);

//	kthread_stop(data->thread); //让刷图线程退出
//	dma_free_coherent(dev->dev, fbi->screen_size, fbi->screen_base, fbi->fix.smem_start);
}

static void  SPI_WriteData(struct st7735s_st *dev, u8 Data)
{
	unsigned char i=0;
	for(i=8;i>0;i--)
	{
	  if(Data&0x80)
	  {
		  gpio_set_value(dev->gpio_dio, 1);
	  }
      else 
	  {
		  gpio_set_value(dev->gpio_dio, 0);
	  }	  
	  gpio_set_value(dev->gpio_sck, 0);
	  gpio_set_value(dev->gpio_sck, 1);
      Data<<=1; 
	}
}

static void st7735_write_cmd(struct st7735s_st *dev, u8 buf)
{
	gpio_set_value(dev->gpio_cs, 0);
	gpio_set_value(dev->gpio_dc, 0);
	SPI_WriteData(dev, buf);
	gpio_set_value(dev->gpio_cs, 1);
}

static void st7735_write_data(struct st7735s_st *dev, u8 buf)
{
	gpio_set_value(dev->gpio_cs, 0);
	gpio_set_value(dev->gpio_dc, 1);
	SPI_WriteData(dev, buf);
	gpio_set_value(dev->gpio_cs, 1);
}

static void init_st7735(struct st7735s_st *me)
{
	gpio_set_value(me->gpio_rst, 0);//复位
	mdelay(100);
	gpio_set_value(me->gpio_rst, 1);
    mdelay(100);  

	//--------------------Start Initial Sequence-------------------//
	st7735_write_cmd(me, 0x11);     //Sleep out
	mdelay(120);                	//Delay 120ms

	st7735_write_cmd(me, 0x21); 
	st7735_write_cmd(me, 0xB1);     
	st7735_write_data(me, 0x05);   
	st7735_write_data(me, 0x3A);   
	st7735_write_data(me, 0x3A);   

	st7735_write_cmd(me, 0xB2);     
	st7735_write_data(me, 0x05);   
	st7735_write_data(me, 0x3A);   
	st7735_write_data(me, 0x3A);   

	st7735_write_cmd(me, 0xB3);     
	st7735_write_data(me, 0x05);   
	st7735_write_data(me, 0x3A);   
	st7735_write_data(me, 0x3A);   
	st7735_write_data(me, 0x05);   
	st7735_write_data(me, 0x3A);   
	st7735_write_data(me, 0x3A);   

	st7735_write_cmd(me, 0xB4);     //Dot inversion
	st7735_write_data(me, 0x03);   

	st7735_write_cmd(me, 0xC0);     
	st7735_write_data(me, 0x62);   
	st7735_write_data(me, 0x02);   
	st7735_write_data(me, 0x04);   

	st7735_write_cmd(me, 0xC1);     
	st7735_write_data(me, 0xC0);   

	st7735_write_cmd(me, 0xC2);     
	st7735_write_data(me, 0x0D);   
	st7735_write_data(me, 0x00);   

	st7735_write_cmd(me, 0xC3);     
	st7735_write_data(me, 0x8D);   
	st7735_write_data(me, 0x6A);   

	st7735_write_cmd(me, 0xC4);     
	st7735_write_data(me, 0x8D);   
	st7735_write_data(me, 0xEE);   

	st7735_write_cmd(me, 0xC5);     //VCOM
	st7735_write_data(me, 0x0E);   

	st7735_write_cmd(me, 0xE0);
	st7735_write_data(me, 0x10);
	st7735_write_data(me, 0x0E);
	st7735_write_data(me, 0x02);
	st7735_write_data(me, 0x03);
	st7735_write_data(me, 0x0E);
	st7735_write_data(me, 0x07);
	st7735_write_data(me, 0x02);
	st7735_write_data(me, 0x07);
	st7735_write_data(me, 0x0A);
	st7735_write_data(me, 0x12);
	st7735_write_data(me, 0x27);
	st7735_write_data(me, 0x37);
	st7735_write_data(me, 0x00);
	st7735_write_data(me, 0x0D);
	st7735_write_data(me, 0x0E);
	st7735_write_data(me, 0x10);

	st7735_write_cmd(me, 0xE1);
	st7735_write_data(me, 0x10);
	st7735_write_data(me, 0x0E);
	st7735_write_data(me, 0x03);
	st7735_write_data(me, 0x03);
	st7735_write_data(me, 0x0F);
	st7735_write_data(me, 0x06);
	st7735_write_data(me, 0x02);
	st7735_write_data(me, 0x08);
	st7735_write_data(me, 0x0A);
	st7735_write_data(me, 0x13);
	st7735_write_data(me, 0x26);
	st7735_write_data(me, 0x36);
	st7735_write_data(me, 0x00);
	st7735_write_data(me, 0x0D);
	st7735_write_data(me, 0x0E);
	st7735_write_data(me, 0x10);

	st7735_write_cmd(me, 0x3A);   
	st7735_write_data(me, 0x05);   

	st7735_write_cmd(me, 0x36);     
	st7735_write_data(me, 0xA8);   

	st7735_write_cmd(me, 0x29);  
}

static void LCD_SetWindows(struct st7735s_st *me, u16 xStar, u16 yStar,u16 xEnd,u16 yEnd)
{	
	st7735_write_cmd(me, 0x2a);	
	st7735_write_data(me,0x00);
	st7735_write_data(me,xStar);		
	st7735_write_data(me,0x00);
	st7735_write_data(me,xEnd);

	st7735_write_cmd(me, 0x2b);
	st7735_write_data(me,0x00);
	st7735_write_data(me,yStar+24);		
	st7735_write_data(me,0x00);
	st7735_write_data(me,yEnd+24);

	st7735_write_cmd(me, 0x2C);
}  

static void LCD_Clear(struct st7735s_st *me, u16 color)
{
	u16 i,j; 
	LCD_SetWindows(me,0,0,LCD_W-1,LCD_H-1);
    for(i=0;i<LCD_W;i++)
	{
	  	for (j=0;j<LCD_H;j++)
		{	
			st7735_write_data(me, ~((color>>8)&0xff));
          	st7735_write_data(me, ~(color&0xff));
		}
	}
}

static void show_fb(struct st7735s_st *me)
{
    int x, y;
    u32 k;
    u32 *p = (u32 *)(me->fbi->screen_base);
    u16 c;
    u8 *pp;

    LCD_SetWindows(me,0,0,LCD_W-1,LCD_H-1); //从屏的0,0坐标开始刷
    for (y = 0; y < me->fbi->var.yres; y++)
    {
        for (x = 0; x < me->fbi->var.xres; x++)
        {
            k = p[y*me->fbi->var.xres+x];//取出一个像素点的32位数据
            // rgb8888 --> rgb565       
            pp = (u8 *)&k;  
            c = pp[0] >> 3; //蓝色
            c |= (pp[1]>>2)<<5; //绿色
            c |= (pp[2]>>3)<<11; //红色

            //发出像素数据的rgb565
			st7735_write_data(me, ~((c>>8)&0xff));
          	st7735_write_data(me, ~(c&0xff));
        }
    }
}

static int getGPIOs(struct st7735s_st *me)
{
	int ret =0;

	//获取GPIO
	me->gpio_cs  = of_get_named_gpio(me->node, "gpio_cs", 0);
	if(me->gpio_cs<0)
	{
		printk("gpio_cs get error\r\n");
		return -EINVAL;
	}
	
	me->gpio_dc  = of_get_named_gpio(me->node, "gpio_dc", 0);
	if(me->gpio_dc<0)
	{
		printk("gpio_dc get error\r\n");
		return -EINVAL;
	}
	
	me->gpio_rst = of_get_named_gpio(me->node, "gpio_rst", 0);
	if(me->gpio_rst<0)
	{
		printk("gpio_rst get error\r\n");
		return -EINVAL;
	}

	
	me->gpio_dio = of_get_named_gpio(me->node, "gpio_dio", 0);
	if(me->gpio_dio<0)
	{
		printk("gpio_dio get error\r\n");
		return -EINVAL;
	}

	me->gpio_sck = of_get_named_gpio(me->node, "gpio_sck", 0);
	if(me->gpio_sck<0)
	{
		printk("gpio_sck get error\r\n");
		return -EINVAL;
	}

	//申请GPIO
	ret = gpio_request(me->gpio_cs, "gpio_cs");
	if(ret <0)
	{
		printk("gpio_cs request error\r\n");
		goto gpio_cs_err;
	}

	ret = gpio_request(me->gpio_dc, "gpio_dc");
	if(ret <0)
	{
		printk("gpio_dc request error\r\n");
		goto gpio_dc_err;
	}

	ret = gpio_request(me->gpio_rst, "gpio_rst");
	if(ret <0)
	{
		printk("gpio_rst request error\r\n");
		goto gpio_rst_err;
	}

	ret = gpio_request(me->gpio_dio, "gpio_dio");
	if(ret <0)
	{
		printk("gpio_dio request error\r\n");
		goto gpio_gpio_dio;
	}

	ret = gpio_request(me->gpio_sck, "gpio_sck");
	if(ret <0)
	{
		printk("gpio_sck request error\r\n");
		goto gpio_gpio_sck;
	}

	//设置GPIO输出
	gpio_direction_output(me->gpio_cs, 1);
	gpio_direction_output(me->gpio_dc, 1);
	gpio_direction_output(me->gpio_rst, 1);
	gpio_direction_output(me->gpio_dio, 1);
	gpio_direction_output(me->gpio_sck, 1);

	return 0;

gpio_gpio_sck:
	gpio_free(me->gpio_dio);
gpio_gpio_dio:
	gpio_free(me->gpio_rst);
gpio_rst_err:
	gpio_free(me->gpio_dc);
gpio_dc_err:
	gpio_free(me->gpio_cs);
gpio_cs_err:
	return ret;
}

static int st7735s_probe(struct platform_device *dev)
{
	int ret =0;
	
	st7735sDev.node = dev->dev.of_node;
	//获取GPIO
	ret = getGPIOs(&st7735sDev);
	if(ret <0)
	{
		printk("getGPIOs error\r\n");
		goto getGPIO_err;
	}

	//初始化显示屏
	init_st7735(&st7735sDev);

	//初始化显示设备
	myfb_new(&st7735sDev);
	
	printk("st7735s_probe sucess\r\n");
	return 0;
	
getGPIO_err:
	return ret;
}

static int st7735s_remove(struct platform_device *dev)
{
	//关闭GPIO
	gpio_set_value(st7735sDev.gpio_cs, 1);
	gpio_set_value(st7735sDev.gpio_dc, 1);
	gpio_set_value(st7735sDev.gpio_rst, 1);
	gpio_set_value(st7735sDev.gpio_dio, 0);
	gpio_set_value(st7735sDev.gpio_sck, 0);

	//释放GPIO
	gpio_free(st7735sDev.gpio_cs);
	gpio_free(st7735sDev.gpio_dc);
	gpio_free(st7735sDev.gpio_rst);
	gpio_free(st7735sDev.gpio_dio);
	gpio_free(st7735sDev.gpio_sck);

	//释放fb设备
	myfb_del(&st7735sDev);
	printk("st7735s_remove sucess\r\n");
	return 0;
}

static const struct platform_device_id st7735s_id[] = 
{
	{"st7735s",0},
	{}	
};

static const struct of_device_id st7735s_of_match[]=
{
	{.compatible="st7735s"},
	{}
};

static struct platform_driver st7735s_dev = 
{
	.probe  = st7735s_probe,
	.remove = st7735s_remove,
	.driver = {
		.owner = THIS_MODULE,
		.name  = "st7735s",
		.of_match_table = st7735s_of_match,
	},
	.id_table = st7735s_id,
};

static int __init st7735s_init(void)
{
	return platform_driver_register(&st7735s_dev);
}

static void __exit st7735s_exit(void)
{
	platform_driver_unregister(&st7735s_dev);
}

module_init(st7735s_init);
module_exit(st7735s_exit);
MODULE_AUTHOR("jtb");
MODULE_LICENSE("GPL");


